package tunnel

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"sync"
	"time"

	"internal-net-bridge-server/internal/models"
	"internal-net-bridge-server/internal/tunnel/protocols/common"
	httpProto "internal-net-bridge-server/internal/tunnel/protocols/http"
)

// RequestTracker 用于跟踪请求的状态
type RequestTracker struct {
	mutex    sync.RWMutex
	requests map[string]bool // requestID -> isCancelled
}

// NewRequestTracker 创建请求跟踪器
func NewRequestTracker() *RequestTracker {
	return &RequestTracker{
		requests: make(map[string]bool),
	}
}

// MarkCancelled 标记请求为已取消
func (rt *RequestTracker) MarkCancelled(requestID string) {
	rt.mutex.Lock()
	defer rt.mutex.Unlock()
	rt.requests[requestID] = true
}

// IsCancelled 检查请求是否已取消
func (rt *RequestTracker) IsCancelled(requestID string) bool {
	rt.mutex.RLock()
	defer rt.mutex.RUnlock()
	cancelled, exists := rt.requests[requestID]
	return exists && cancelled
}

// startPublicPortListener 启动公共端口监听器
// 这个函数为隧道的公共端口创建一个TCP监听器，接收外部客户端（浏览器）的连接请求
func (tm *TunnelManager) startPublicPortListener(tunnel *models.Tunnel) {
	publicPort := tunnel.PublicPort
	if publicPort == "" || publicPort == "0" {
		log.Printf("⚠️ 隧道 %s 没有配置公共端口，跳过公共端口监听", tunnel.ID)
		return
	}

	listener, err := net.Listen("tcp", fmt.Sprintf(":%s", publicPort))
	if err != nil {
		log.Printf("❌ 公共端口监听失败 %s: %v", publicPort, err)
		return
	}

	tunnel.PublicListener = listener
	log.Printf("🌐 公共端口监听启动成功: :%s -> 隧道 %s", publicPort, tunnel.ID)

	// 创建TCP优化器
	tcpOptimizer := common.NewTCPOptimizer()

	// 创建请求跟踪器
	requestTracker := NewRequestTracker()

	// 启动连接接收循环
	for {
		clientConn, err := listener.Accept()
		if err != nil {
			// 检查是否是因为监听器被关闭
			if opErr, ok := err.(*net.OpError); ok && opErr.Err.Error() == "use of closed network connection" {
				log.Printf("🔌 公共端口监听器已关闭: :%s", publicPort)
				return
			}
			log.Printf("⚠️ 接受连接失败 (端口:%s): %v", publicPort, err)
			continue
		}

		// 优化TCP连接（应用BBR/CUBIC拥塞控制）
		if err := tcpOptimizer.OptimizeConnection(clientConn); err != nil {
			log.Printf("⚠️ [公共端口:%s] TCP连接优化失败: %v", publicPort, err)
			// 继续处理连接，即使优化失败
		}

		// 异步处理每个客户端连接
		go tm.handlePublicPortConnection(tunnel, clientConn, requestTracker)
	}
}

// StartPublicPortListenerForTunnelID 为指定的隧道ID启动公共端口监听器
// 这个方法用于API层在创建隧道后启动监听器
func (tm *TunnelManager) StartPublicPortListenerForTunnelID(tunnelID string, publicPort int64) error {
	tm.mutex.Lock()
	defer tm.mutex.Unlock()

	// 检查隧道是否已经存在
	tunnel, exists := tm.tunnels[tunnelID]
	if !exists {
		// 隧道不存在，创建一个简化的Tunnel对象用于监听
		// 注意：这个Tunnel对象主要用于公共端口监听，详细信息在数据库中
		tunnel = &models.Tunnel{
			ID:         tunnelID,
			PublicPort: fmt.Sprintf("%d", publicPort),
			RequestMap: make(map[string]*models.HTTPRequest),
		}
		tm.tunnels[tunnelID] = tunnel
		portKey := fmt.Sprintf("%d", publicPort)
		tm.portMappings[portKey] = tunnel
	}

	// 🔥 检查是否已经有新的协议监听器
	if tm.protocolFactory != nil {
		existingListener := tm.GetProtocolListener(tunnelID)
		if existingListener != nil {
			log.Printf("ℹ️  隧道 %s 已有协议监听器运行，跳过启动", tunnelID[:8]+"...")
			return nil
		}

		// 使用新的协议监听器
		log.Printf("🚀 使用协议工厂启动监听器: 隧道=%s, 端口=%d", tunnelID[:8]+"...", publicPort)
		go tm.startProtocolListener(tunnel)
		return nil
	}

	// 向后兼容：检查旧的监听器
	if tunnel.PublicListener != nil {
		log.Printf("ℹ️  公共端口 :%d 已有监听器运行，跳过启动", publicPort)
		return nil
	}

	// 启动公共端口监听器（旧版）
	log.Printf("⚠️ 协议工厂未初始化，使用旧版监听器")
	go tm.startPublicPortListener(tunnel)
	log.Printf("🚀 已为隧道 %s 启动公共端口监听器: :%d", tunnelID, publicPort)

	return nil
}

// handlePublicPortConnection 处理公共端口的客户端连接
// 这个函数接收浏览器的HTTP请求，通过QUIC隧道转发给客户端
func (tm *TunnelManager) handlePublicPortConnection(tunnel *models.Tunnel, clientConn net.Conn, requestTracker *RequestTracker) {
	defer clientConn.Close()

	clientAddr := clientConn.RemoteAddr().String()
	log.Printf("🌐 收到HTTP请求: 客户端=%s, 隧道ID=%s", clientAddr, tunnel.ID)

	// 检查QUIC服务器是否可用
	if tm.quicServer == nil {
		log.Printf("❌ QUIC服务器未初始化")
		// 🎨 返回"服务器未启动"页面
		errorHTML := `HTTP/1.1 503 Service Unavailable\r\nContent-Type: text/html\r\n\r\n<html><body><h1>Service Unavailable</h1><p>QUIC server not initialized</p></body></html>`
		clientConn.Write([]byte(errorHTML))
		return
	}

	// 读取HTTP请求
	reader := bufio.NewReader(clientConn)

	// 读取请求行
	requestLine, err := reader.ReadString('\n')
	if err != nil {
		log.Printf("❌ HTTP请求读取失败: %v", err)
		return
	}

	// 读取请求头
	headers := []string{requestLine}
	contentLength := 0
	isChunked := false

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			log.Printf("❌ HTTP请求头读取失败: %v", err)
			return
		}

		headers = append(headers, line)

		// 检查Content-Length
		if len(line) > 16 && (line[:16] == "Content-Length: " || line[:16] == "content-length: ") {
			fmt.Sscanf(line[16:], "%d", &contentLength)
		}

		// 🔥 检查是否使用chunked编码
		if strings.Contains(strings.ToLower(line), "transfer-encoding: chunked") {
			isChunked = true
		}

		// 空行表示头部结束
		if line == "\r\n" || line == "\n" {
			break
		}
	}

	// 🔥🔥🔥 关键优化：大文件上传不缓存到内存，使用服务端缓存+客户端拉取
	// 🧪 临时降低阈值到500KB以测试新架构（生产环境建议10MB）
	const MAX_BODY_CACHE = 500 * 1024 // 500KB阈值（测试用）

	var body []byte
	var bodyReader io.Reader

	if contentLength > 0 {
		if contentLength <= MAX_BODY_CACHE {
			// 小文件：读取到内存（兼容旧逻辑）
			body = make([]byte, contentLength)
			// 使用io.ReadFull确保完整读取Body
			n, err := io.ReadFull(reader, body)
			if err != nil {
				log.Printf("❌ HTTP请求体读取失败: %v (已读取=%d, 期望=%d)", err, n, contentLength)
				return
			}
			log.Printf("✅ 读取完整请求体: %d bytes (缓存到内存)", n)
		} else {
			// 🔥 大文件：使用LimitedReader流式读取
			bodyReader = io.LimitReader(reader, int64(contentLength))
			log.Printf("🚀 大文件上传检测: %d bytes，使用流式转发", contentLength)
		}
	} else if isChunked {
		// 🔥 Chunked编码：不限制长度，直接读取到EOF
		bodyReader = reader
		log.Printf("🚀 检测到chunked编码，使用流式转发")
	}

	// 🔥🔥🔥 关键优化：大文件上传改为缓存到服务端，客户端主动拉取
	if bodyReader != nil {
		// 生成请求ID（用于缓存标识）
		requestID := fmt.Sprintf("%s-%019d", tunnel.ID[:16], time.Now().UnixNano())
		
		log.Printf("🚀 [大文件上传] 检测到大文件: Size=%d bytes, RequestID=%s",
			contentLength, requestID[:8]+"...")

		// 读取整个Body到内存（用于缓存）
		startTime := time.Now()
		bodyData, err := io.ReadAll(bodyReader)
		if err != nil {
			log.Printf("❌ [大文件上传] Body读取失败: %v", err)
			errorHTML := `HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\n上传失败`
			clientConn.Write([]byte(errorHTML))
			return
		}
		readDuration := time.Since(startTime)
		
		log.Printf("✅ [大文件上传] Body读取完成: Size=%.2f MB, 耗时=%.2fs",
			float64(len(bodyData))/(1024*1024), readDuration.Seconds())

		// 组装完整的HTTP请求
		var httpReq []byte
		for _, header := range headers {
			httpReq = append(httpReq, []byte(header)...)
		}
		httpReq = append(httpReq, bodyData...)

		// 解析请求头（用于缓存元数据）
		headerMap := make(map[string]string)
		contentType := "application/octet-stream"
		requestPath := ""
		requestMethod := "POST"

		// 解析第一行：方法和路径
		parts := strings.Split(requestLine, " ")
		if len(parts) >= 2 {
			requestMethod = parts[0]
			requestPath = parts[1]
		}

		// 解析请求头
		for _, header := range headers[1:] { // 跳过第一行
			if header == "\r\n" || header == "\n" {
				break
			}
			colonIdx := strings.Index(header, ":")
			if colonIdx > 0 {
				key := strings.TrimSpace(header[:colonIdx])
				value := strings.TrimSpace(header[colonIdx+1:])
				headerMap[strings.ToLower(key)] = value

				if strings.ToLower(key) == "content-type" {
					contentType = value
				}
			}
		}

		// 缓存到服务端
		cachedUpload := &httpProto.CachedUpload{
			RequestID:     requestID,
			TunnelID:      tunnel.ID,
			Method:        requestMethod,
			Path:          requestPath,
			Headers:       headerMap,
			Body:          bodyData,
			ContentType:   contentType,
			ContentLength: int64(contentLength), // 原始Content-Length（chunked时为0）
			IsChunked:     isChunked,            // 🆕 标记是否为chunked编码
		}

		if err := tm.uploadCacheManager.Cache(requestID, cachedUpload); err != nil {
			log.Printf("❌ [大文件上传] 缓存失败: %v", err)
			errorHTML := `HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\n缓存失败`
			clientConn.Write([]byte(errorHTML))
			return
		}

		// 🚀🚀🚀 关键架构：通过QUIC发送通知，等待响应，转发给浏览器
		// 这里使用同步方式，保持browserConn打开直到收到客户端响应
		log.Printf("🔔 [大文件上传] 发送通知给客户端，等待处理: RequestID=%s", requestID[:8]+"...")
		
		if err := httpProto.SendUploadNotification(tm.quicServer, tunnel.ID, requestID, clientConn); err != nil {
			log.Printf("❌ [大文件上传] 通知失败: %v", err)
			errorHTML := `HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\n处理失败`
			clientConn.Write([]byte(errorHTML))
			return
		}
		
		// ✅ sendUploadNotification已经将响应转发给浏览器了
		log.Printf("✅ [大文件上传] 处理完成并已返回响应: RequestID=%s", requestID[:8]+"...")
		return
	}

	// 组装完整的HTTP请求（仅用于小文件）
	var httpReq []byte
	for _, header := range headers {
		httpReq = append(httpReq, []byte(header)...)
	}
	httpReq = append(httpReq, body...)

	// 生成请求ID（36字节固定长度，与协议匹配）
	// 格式: 16字符TunnelID前缀 + "-" + 19位时间戳 = 36字符
	// UnixNano()返回19位数字（例如：1762088764058207000）
	requestID := fmt.Sprintf("%s-%019d", tunnel.ID[:16], time.Now().UnixNano())

	log.Printf("📋 HTTP请求详情: %s (头部=%d, 体=%d bytes, RequestID=%s)",
		requestLine[:len(requestLine)-2], len(headers), len(body), requestID[:8]+"...")

	// 检查请求是否已被取消
	if requestTracker.IsCancelled(requestID) {
		log.Printf("🚫 请求已被取消，跳过处理: RequestID=%s", requestID[:8]+"...")
		return
	}

	// 通过QUIC隧道发送请求给客户端
	err = tm.quicServer.SendRequestToClient(tunnel.ID, requestID, httpReq, clientConn)
	if err != nil {
		log.Printf("❌ QUIC隧道转发失败: %v", err)
		// 标记请求为已取消
		requestTracker.MarkCancelled(requestID)
		return
	}

	log.Printf("🔄 HTTP请求处理完成，连接将由响应转发机制管理 (客户端: %s)", clientAddr)
}
